package xin.ham.aprs4gserv.controller;

import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import xin.ham.aprs4gserv.entity.Aprs4GConf;
import xin.ham.aprs4gserv.entity.Response;
import xin.ham.aprs4gserv.mapper.ConfMapper;

import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

@Slf4j
@Controller
@RequestMapping("/aprs4g")
public class Aprs4GController {
    private final Cache<String,String> fifoCache = CacheUtil.newFIFOCache(30);
    @Autowired
    private ConfMapper devMapper;

    @Value("${talk.file.path}")
    private String talkfilepath;

    @ResponseBody
    @PostMapping("/uploadconf")
    public Response<?> uploadconf (@RequestBody Aprs4GConf aprs4GConf){
        log.info("uploadconf: {}", JSONUtil.toJsonStr(aprs4GConf));
        aprs4GConf.setCurdate(DateUtil.now());
        Long saved = devMapper.selectCount(new QueryWrapper<Aprs4GConf>().eq("imei", aprs4GConf.getImei()));
        if (saved <= 0) {
            int insert = devMapper.insert(aprs4GConf);
            log.info("insert {}", insert);
        } else {
            int update = devMapper.updateById(aprs4GConf);
            log.info("update {}", update);
        }
        return Response.ok(aprs4GConf);
    }

    @RequestMapping("/devs")
    public String devs(Model model){
        List<Aprs4GConf> aprs4GConfs = devMapper.selectList(new QueryWrapper<>());
        model.addAttribute("devs", aprs4GConfs);
        return "devs";
    }

    @ResponseBody
    @PostMapping("/deldev")
    public Response<?> deldev(@RequestParam("imei") String imei){
        log.info("deldev {}", imei);
        fifoCache.remove(imei);
        devMapper.deleteById(imei);
        return Response.ok();
    }

    @RequestMapping("/conf")
    public String conf(@RequestParam("imei") String imei, Model model){
        if (StrUtil.isEmptyIfStr(imei) || !StrUtil.isNumeric(imei)) {
            return "500";
        }
        Aprs4GConf aprs4GConf = devMapper.selectOne(new QueryWrapper<Aprs4GConf>().eq("imei", imei));
        log.info("conf: {}", JSONUtil.toJsonStr(aprs4GConf));
        model.addAttribute("dev", aprs4GConf);
        return "conf";
    }

    @ResponseBody
    @PostMapping("/takeeffect")
    public Response<?> takeEffect(@RequestBody Aprs4GConf aprs4GConf){
        log.info("takeEffect {}", JSONUtil.toJsonStr(aprs4GConf));
        fifoCache.put(aprs4GConf.getImei(), JSONUtil.toJsonStr(aprs4GConf), DateUnit.SECOND.getMillis() * 60);
        return Response.ok();
    }
    @ResponseBody
    @PostMapping("/updateconf")
    public Response<?> updateconf(@RequestParam("imei") String imei){
        log.info("updateconf {}", imei);

        String conf = fifoCache.get(imei);
        if (conf != null) {
            Aprs4GConf aprs4gconf = JSONUtil.toBean(conf, Aprs4GConf.class);
            fifoCache.remove(imei);
            return Response.ok(aprs4gconf.toClientConf());
        } else {
            return Response.error("配置已失效");
        }

    }
    @ResponseBody
    @PostMapping("/upload")
    public Response<?> uploadSingleFile(@RequestParam("file") MultipartFile file) {
        if(file.getSize() > 0){
            String fn = IdUtil.simpleUUID();
            try {
                FileUtil.writeBytes(file.getBytes(), talkfilepath+fn+".amr");
            } catch (IOException e) {
                return Response.error();
            }
            return Response.ok(fn);
        } else {
            return Response.error();
        }
    }

    @GetMapping("/download/{key}")
    public ResponseEntity<Resource> downloadFile(@PathVariable String key) throws IOException {
        try {
            checkSpecChar(key);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        Path path = Paths.get(talkfilepath+key+".amr").toAbsolutePath(); // 替换为你的文件路径
        Resource resource = new UrlResource(path.toUri());
        if (resource.exists() || resource.isReadable()) {
            return ResponseEntity.ok()
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .header("Content-Disposition", "attachment; filename=\"" + "msg.amr" + "\"") // 设置文件名
                    .body(resource);
        } else {
            throw new RuntimeException("File not found");
        }
    }

    private void checkSpecChar(String input) throws Exception{
        if( input != null ){
            String[] chars = ";,|,&,$,%,<,>,(,),+,',\",\\,\\\\,..".split(",");
            for( String s : chars ){
                if( input.contains(s)){
                    throw new Exception("非法字符.");
                }
            }
        }
    }
}
